Day 5 建立了 app.db 和測試資料。現在只能透過 Python 腳本查詢,前端和其他工具還沒有入口。
今天用 FastAPI 建立第一批 API:
FastAPI 負責接收請求、驗證資料、執行程式邏輯,再回傳 JSON。它也會根據路由和 Pydantic schema 自動產生互動式 API 文件。
使用者發出請求
↓
FastAPI 接收並驗證格式
↓
執行程式邏輯或查詢資料庫
↓
回傳 JSON
進入 backend:
cd backend
python -m pip install fastapi uvicorn
確認 FastAPI:
python -c "import fastapi; print(fastapi.__version__)"
檔案位置:backend/main.py
from fastapi import FastAPI
app = FastAPI(title="AI 學習教練 API")
@app.get("/")
def read_root() -> dict:
"""根路徑,確認服務活著"""
return {"message": "AI 學習教練 API 運行中"}
啟動:
uvicorn main:app --reload
開啟 http://127.0.0.1:8000,應該看到:
{"message": "AI 學習教練 API 運行中"}
-- reload 會在開發期間偵測程式碼變更並重新啟動伺服器。
在 backend/main.py 繼續加入:
@app.get("/health")
def health_check() -> dict:
"""健康檢查端點,回傳服務狀態"""
return {"status": "ok"}
開啟 http://127.0.0.1:8000/health:
{"status": "ok"}
Day 23 的 Next.js 前端預計使用 localhost:3000,FastAPI 使用 localhost:8000。瀏覽器會把它們視為不同來源,因此後端要先允許前端網址。
在 main.py 加入:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
正式部署時,allow_origins 應該改成實際的前端網址,不要長期開放所有來源。
接上 Day 5 的 database.py 和 models.py:
from fastapi import Depends
from sqlalchemy.orm import Session
from database import get_db
from models import User, Plan
@app.get("/users/count")
def count_users(db: Session = Depends(get_db)) -> dict:
"""查詢目前使用者總數"""
total = db.query(User).count()
return {"total_users": total}
@app.get("/plans/count")
def count_plans(db: Session = Depends(get_db)) -> dict:
"""查詢目前計畫總數"""
total = db.query(Plan).count()
return {"total_plans": total}
Depends(get_db) 是 FastAPI 的依賴注入。每次收到請求時,FastAPI 會建立 Session;請求完成後,get_db 的 finally 會關閉連線。
如果先執行過 Day 5 的 init_db.py:
{"total_users": 1}
GET 用來查資料,POST 用來送資料。用 Pydantic 定義請求格式:
from pydantic import BaseModel
class EchoMessage(BaseModel):
text: str
@app.post("/echo")
def echo_message(payload: EchoMessage) -> dict:
"""回傳收到的訊息,驗證 POST 請求能正常運作"""
return {"you_said": payload.text}
可以從 http://127.0.0.1:8000/docs 測試:
{"text": "Hello FastAPI"}
{"you_said": "Hello FastAPI"}
如果缺少 text 或型別不符合,FastAPI 會回傳驗證錯誤。
也可以用 requests 測試:
python -c "import requests; print(requests.post('http://127.0.0.1:8000/echo', json={'text': 'Hello FastAPI'}).json())"
執行前安裝 requests:
python -m pip install requests
開啟 http://127.0.0.1:8000/docs,可以看到目前所有 API。每個端點都有請求格式、參數和回應 schema,也能直接執行測試。
這個頁面由 FastAPI 根據程式碼自動產生,後續每增加一支 API,文件也會同步出現。
確認已安裝 uvicorn,並在 backend 目錄執行:
python -m pip install uvicorn
先確認 app.db 已存在,並執行過 Day 5 的 init_db.py。
8000 已被其他程式使用,可以改用 8001:
uvicorn main:app --reload --port 8001
確認 allow_origins 的網址和前端實際網址完全相同,包含 port。
確認啟動指令包含 --reload,或手動停止後重新啟動伺服器。
今天完成:
目前進度:
Day 1 ✓ 產品定義完成
Day 2 ✓ 開發環境準備
Day 3 ✓ 專案架構設計
Day 4 ✓ 資料庫設計
Day 5 ✓ SQLite 資料庫建置
Day 6 ✓ FastAPI 基礎
Day 7 ⬜ 使用者檔案 API
明天開始寫第一支真正給使用者使用的 API:建立與查詢學習檔案。